Skip to content

Conversation

@Zetazzz
Copy link
Contributor

@Zetazzz Zetazzz commented Jan 8, 2026

Summary

  • Consolidate the jobs runtime into knative-job-service (callback server, worker/scheduler, and functions) and wire cnc jobs up to it.
  • Add and harden jobs E2E coverage (success + failure cases) with GraphQL started inside the test.
  • Switch cloud functions to SMTP via the new smtppostmaster package and improve logging/diagnostics.

Changes

  • Promote knative-job-service to the primary jobs runtime (KnativeJobsSvc) with env-based boot helpers and function orchestration.
  • Move jobs E2E test + fixtures under jobs/knative-job-service, start GraphQL server in-test, and add failure scenarios.
  • Add @constructive-io/smtppostmaster and update simple-email/send-email-link to use SMTP.
  • improve logging formatting.
  • wire cnc jobs up to knative-job-service

Testing

  • pnpm --filter @constructive-io/knative-job-service test -- jobs.e2e.test.ts

Note

Introduces a unified jobs runtime and optional SMTP email sending with improved logging and shutdown handling.

  • Consolidates jobs runtime into jobs/knative-job-service (KnativeJobsSvc): orchestrates callback server, worker, scheduler, and function services; adds env-based boot helpers and graceful stop/UNLISTEN cleanup
  • Adds CLI integration: new cnc jobs up command wired to knative-job-service
  • Adds SMTP sender: new @constructive-io/smtppostmaster package; functions simple-email and send-email-link can switch via EMAIL_SEND_USE_SMTP
  • Improves logging: move to @pgpmjs/logger (adds createLogger, better formatting) across jobs/functions/servers
  • GraphQL server hardening: return HttpServer, add listen/close lifecycle, cache cleanup, pg/graphile cache clear hooks
  • Env/types support: extend @pgpmjs/env (+parseEnvNumber, SMTP config) and @pgpmjs/types (SmtpOptions, defaults)
  • E2E tests: new jobs.e2e.test.ts with seeded DB; spins up GraphQL + jobs + functions; covers success, failure, retries, and mail provider errors; CI runs jobs/knative-job-service
  • Minor: refactor @constructive-io/knative-job-fn to createJobApp, improved callback/error handling; worker/scheduler/job-pg add graceful shutdown

Written by Cursor Bugbot for commit ada5524. This will update automatically on new commits. Configure here.

@Zetazzz Zetazzz marked this pull request as draft January 8, 2026 02:09
@Zetazzz Zetazzz marked this pull request as ready for review January 18, 2026 04:32
try {
return JSON.stringify(obj, null, 2);
} catch {
return '[Unserializable Object]';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did something become unserializable @Zetazzz ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Things with circular refs, rarely happen, but they cause JSON.stringify failure

const resolvedSecure = secureFromEnv ?? resolvedPort === 465;

const user = process.env.SMTP_USER;
const pass = process.env.SMTP_PASS;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we move all of the process.env into our environment system instead of inlined?

I think pgpm/env or pgpm/types and we can use the defaults system, too

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there should be no process.env in any modules — all hoisted into env/types (like telescope)

maxMessages?: number;
};

const parseNumberFromEnv = (name: string) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you hoist the types/env stuff you can likely get rid of this too, and it looks duplicative of stuff we already have in the getEnvOptions and family

@@ -0,0 +1,164 @@
import nodemailer, { SendMailOptions } from 'nodemailer';
import SMTPTransport from 'nodemailer/lib/smtp-transport';
import { parseEnvBoolean, parseEnvNumber } from '@pgpmjs/env';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of importing these low-level methods, we should just be calling one of the getEnv here

const catcher = useCatcher ? await createSmtpCatcher() : null;

if (catcher) {
process.env.SMTP_HOST = catcher.host;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar advice? (regarding many env vars)

I guess for tests it would be slightly more acceptable, but maybe we can just use overrides and call a getEnv from @pgpm/env or @pgpm/types

import { send } from '../src/index';
import { createSmtpCatcher } from './smtp-catcher';

const applyEnv = (overrides: Record<string, string | undefined>) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's not do this and properly use the env vars from types/env packages

- Add SmtpOptions interface and defaults to @pgpmjs/types
- Add SMTP_* env var parsing to @pgpmjs/env getEnvVars()
- Refactor smtppostmaster to use getEnvOptions() instead of direct process.env
- Add smtpOverrides parameter to send() for programmatic configuration
- Add resetTransport() helper for test isolation
- Update tests to use smtpOverrides instead of env manipulation
- Update README with new programmatic override examples

Addresses PR #577 feedback to move process.env access into the
centralized environment system.
@pyramation pyramation merged commit 1b70cf8 into main Jan 18, 2026
36 checks passed
@pyramation pyramation deleted the feat/cloud-fn-test branch January 18, 2026 06:10
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

}

return { transport, smtpOpts: cachedSmtpOpts ?? smtpOpts };
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SMTP transport cache persists overrides unexpectedly

Medium Severity

The getTransport function overwrites the module-level transport singleton whenever smtpOverrides is provided. Subsequent calls to send() without overrides will reuse this cached transport, which was configured with the previous override values. This means if someone calls send({...}, { host: 'custom.smtp.com' }) once, all subsequent calls to send({...}) without overrides will continue using custom.smtp.com instead of the environment-configured SMTP server, until resetTransport() is explicitly called.

Fix in Cursor Fix in Web

}

return this.result;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing cleanup on partial function startup failure

Medium Severity

When startFunctions() fails partway through (e.g., second function fails due to port conflict), previously started function servers remain running with no cleanup. The start() method sets this.started = true before starting functions, then if startFunctions() throws, the error propagates without closing the already-started servers in functionServers. These HTTP servers continue running as orphaned resources until process termination. A try/catch in start() that calls cleanup on failure is missing.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants